/* Sinc based filter to emulate the output characteristcs of the Amiga's
   sound system.
   Christopher O'Neill 1/7/06
   Based on Antti S. Lankila's interpolation guide (http://bel.fi/~alankila/modguide/interpolate.txt)
 */

/* Paula's clock = 3546895Hz (PAL) */
const int PAULA_CLOCK = 3546895;

#include "AmigaFilter.h"
#include <stdio.h>
#include <string.h>
#include "computed-blep.h"

void AmigaFilter::setFilterType(e_filterType filterType)
{
    filterTable = filterType;
}

void AmigaFilter::setMixerFreq(int frequency)
{
    paulaTicksPerMixerPeriod = PAULA_CLOCK / frequency;
}

void AmigaFilter::setNoteFreq(int frequency)
{
    paulaTicksPerNotePeriod = PAULA_CLOCK / frequency;
}

/* return output simulated as series of bleps */
int16_t AmigaFilter::outputSample()
{
    int i;
    int32_t output;

    output = globalOutputLevel << BLEP_SCALE;
    for (i = 0; i < activeBleps; i += 1)
        output -= winsinc_integral[filterTable][blepState[i].age] * blepState[i].level;
    output >>= BLEP_SCALE;

    if (output < -32768)
        output = -32768;
    else if (output > 32767)
        output = 32767;

    return output;
}

void AmigaFilter::inputSample(int16_t sample, int age)
{
    if (sample != globalOutputLevel)
    {
        /* Start a new blep: level is the difference, age (or phase) is 0 clocks. */
        if (activeBleps > MAX_BLEPS - 1)
        {
            fprintf(stderr, "warning: active blep list truncated!\n");
            activeBleps = MAX_BLEPS - 1;
        }
        /* Make room for new blep */
        memmove(&blepState[1], &blepState[0], sizeof(blepState[0]) * activeBleps);
        /* Update state to account for the new blep */
        activeBleps += 1;
        blepState[0].age = age;
        blepState[0].level = sample - globalOutputLevel;
        globalOutputLevel = sample;
    }
}

void AmigaFilter::advanceClock(const unsigned int cycles)
{
    for (size_t i = 0; i < activeBleps; i += 1)
    {
        blepState[i].age += cycles;
        if (blepState[i].age >= BLEP_SIZE)
        {
            activeBleps = i;
            break;
        }
    }
}

AmigaFilter::e_filterType AmigaFilter::filterTable = AmigaFilter::AMIGA500;
int AmigaFilter::paulaTicksPerMixerPeriod = 74; // default for 48khz